www.gusucode.com > VC++ 虚拟桌面程序源码-源码程序 > VC++ 虚拟桌面程序源码-源码程序/code/VirtualDesktop/VirtualDesktop.cpp

    //Download by http://www.NewXing.com
#include <Windows.h>
#include <Stdio.h>
#include <Tchar.h>
#include <Sddl.h>
#include <Aclapi.h>
#pragma comment(lib, "Advapi32.lib")
#include <Commctrl.h>
#pragma comment(lib,"Comctl32.lib")
#include <Wfext.h> 
#include <Shlobj.h>

#include "VirtualDesktop.h"
#include "Resource.h"

HINSTANCE		g_hinst;
HWND			g_hMainDlg;
HDESK			g_ahDesktop[MAXDESKNUM];
HBITMAP			g_ahBitmap[MAXDESKNUM];
LPTSTR			g_aszDesktopName[MAXDESKNUM];
INT				g_iSelectIndex;
INT				g_iCurrentIndex;
BOOL			g_bHide;
HBITMAP			g_hDrwBmp;
WNDPROC			g_lpfnStcWndFunc;

//获取整个屏幕位图
HBITMAP GetScreenBitmap(LPCRECT lpRect = NULL, BOOL bCursor = FALSE, BOOL bLayered = FALSE)
{
	HBITMAP			hRetBitmap; //返回位图句柄
	HBITMAP			hOldBitmap; //之前的位图句柄
	HDC				hScrDC; //屏幕设备描述表
	HDC				hMemDC; //和内存设备描述表
	RECT			rtCatch; //选中的矩形
	CURSORINFO		curInfo; //鼠标信息
	DWORD			dwRop; //光栅操作代码
	INT				nWidth; //位图宽度
	INT				nHeight; //高度
	INT				xScrn; //屏幕宽度
	INT				yScrn; //屏幕高度
	
	//返回位图句柄置NULL
	hRetBitmap = NULL;
	
	//获取屏幕尺寸
	xScrn = GetSystemMetrics(SM_CXSCREEN);
	yScrn = GetSystemMetrics(SM_CYSCREEN);
		
	//判断矩形是否为NULL
	if(lpRect == NULL)
	{
		//全屏
		rtCatch.left = 0;
		rtCatch.top = 0;
		rtCatch.right = xScrn;
		rtCatch.bottom = yScrn;
	}
	else
	{
		//确保选定区域是可见的
		if(lpRect->left < 0) rtCatch.left = 0;
		else rtCatch.left = lpRect->left;
		if(lpRect->top < 0) rtCatch.top = 0;
		else rtCatch.top = lpRect->top;
		if(lpRect->right > xScrn) rtCatch.right = xScrn;
		else rtCatch.right = lpRect->right;
		if(lpRect->bottom > yScrn) rtCatch.bottom = yScrn;
		else rtCatch.bottom = lpRect->bottom;
	}

	//获取宽高
	nWidth = rtCatch.right - rtCatch.left;
	nHeight = rtCatch.bottom - rtCatch.top;

	//判断矩形是否为空
	if(!IsRectEmpty(&rtCatch))
	{
		//获得屏幕DC
		hScrDC = GetDC(NULL);
		if(hScrDC)
		{	
			//为屏幕设备描述表创建兼容的内存设备描述表
			hMemDC = CreateCompatibleDC(hScrDC);
			if(hMemDC)
			{
				// 创建一个与屏幕设备描述表兼容的位图
				hRetBitmap = CreateCompatibleBitmap(hScrDC, nWidth, nHeight);
				if(hRetBitmap)
				{
					// 把新位图选到内存设备描述表中
					hOldBitmap = (HBITMAP)SelectObject(hMemDC, hRetBitmap);
					
					//是否绘制分层窗口
					dwRop = SRCCOPY | (bLayered ? CAPTUREBLT : 0);

					// 把屏幕设备描述表拷贝到内存设备描述表中
					BitBlt(hMemDC, 0, 0, nWidth, nHeight, hScrDC, rtCatch.left, rtCatch.top, dwRop);
					
					//是否绘制鼠标
					if(bCursor)
					{
						//获取鼠标信息
						curInfo.cbSize = sizeof(CURSORINFO);
						if(GetCursorInfo(&curInfo))
						{
							//绘制鼠标图标
							DrawIconEx(hMemDC,
								curInfo.ptScreenPos.x,
								curInfo.ptScreenPos.y,
								curInfo.hCursor,
								0,
								0,
								FALSE,
								NULL,
								DI_DEFAULTSIZE | DI_NORMAL);
						}
					}

					//得到屏幕位图的句柄
					hRetBitmap = (HBITMAP)SelectObject(hMemDC, hOldBitmap);
				}

				DeleteDC(hMemDC);
			}

			ReleaseDC(NULL, hScrDC);
		}
	}

	return hRetBitmap;
}

//禁止64位文件系统重定向
BOOL MyWow64DisableWow64FsRedirection(PVOID *OldValue)
{
	WOW64DISABLEWOW64FSREDIRECTION		pfnWow64DisableWow64FsRedirection;

	if (!OldValue)
		return FALSE;

	pfnWow64DisableWow64FsRedirection = (WOW64DISABLEWOW64FSREDIRECTION)GetProcAddress(
		GetModuleHandle(_T("Kernel32.dll")), "Wow64DisableWow64FsRedirection");

	if (!pfnWow64DisableWow64FsRedirection)
		return FALSE;

	return pfnWow64DisableWow64FsRedirection(OldValue);
}

//恢复64位文件系统重定向
BOOL MyWow64RevertWow64FsRedirection(PVOID OldValue)
{
	WOW64REVERTWOW64FSREDIRECTION		pfnWow64RevertWow64FsRedirection;

	if (!OldValue)
		return FALSE;

	pfnWow64RevertWow64FsRedirection = (WOW64REVERTWOW64FSREDIRECTION)GetProcAddress(
		GetModuleHandle(_T("Kernel32.dll")), "Wow64RevertWow64FsRedirection");

	if (!pfnWow64RevertWow64FsRedirection)
		return FALSE;

	return pfnWow64RevertWow64FsRedirection(OldValue);
}

//在指定桌面启动进程
BOOL StartProcess(LPTSTR pszDesktopName, LPTSTR pszApplicationName)
{
	STARTUPINFO			si;
	PROCESS_INFORMATION piExplor;

	RtlZeroMemory(&si, sizeof(STARTUPINFO));
    RtlZeroMemory(&piExplor, sizeof(PROCESS_INFORMATION));

	si.cb = sizeof(STARTUPINFO);
    si.lpDesktop = pszDesktopName;
	if(!CreateProcess(pszApplicationName,
		NULL,
		NULL,
		NULL,
		FALSE,
		0,
		NULL,
		NULL,
		&si,
		&piExplor)
       )
        return FALSE;

	CloseHandle(piExplor.hThread);
	CloseHandle(piExplor.hProcess);
	return TRUE;
}

//打开所有桌面,并且初始化所有桌面名
VOID InitAllDesktop()
{
	INT					i;
	
	for(i=0; i<MAXDESKNUM; i++)
	{
		g_aszDesktopName[i] = new TCHAR[MAXDESKNAME];
		if(i == 0)
			lstrcpy(g_aszDesktopName[i], _T("Default"));
		else
			wsprintf(g_aszDesktopName[i], _T("%s%d"), _T("Virtual"), i);
		g_ahDesktop[i] = OpenDesktop(g_aszDesktopName[i], 0, FALSE, GENERIC_ALL);
	}
}

//获取线程所在的桌面
INT GetCurrentDesktopIndex()
{
	HDESK			hThreadDesk;
	TCHAR			szStr[MAXDESKNAME];
	INT				i;
	
	hThreadDesk = GetThreadDesktop(GetCurrentThreadId());//获取线程当前桌面			
	if(GetUserObjectInformation(hThreadDesk,
		UOI_NAME,
		szStr,
		sizeof(szStr),
		NULL))//获取桌面的名称
	{
		for(i=0; i<MAXDESKNUM; i++)
		{
			if(lstrcmpi(szStr, g_aszDesktopName[i]) == 0)
				return i;
		}
	}
	
	return -1;
}

//关闭所有桌面,释放内存
VOID UnInitAllDesktop()
{
	INT					i;

	for(i=0; i<MAXDESKNUM; i++)
	{
		delete []g_aszDesktopName[i];
		g_aszDesktopName[i] = NULL;

		if(g_ahDesktop[i])
		{
			CloseDesktop(g_ahDesktop[i]);
			g_ahDesktop[i] = NULL;
		}
	}
}

//根据全局变量来决定启用或者禁用按钮
VOID EnableButton(HWND hDlg, HDESK *phDesktop)
{
	INT					i;
	HWND				hWnd;

	for(i=0; i<MAXDESKNUM; i++)
	{
		hWnd = GetDlgItem(hDlg, IDC_DESKTOP0 + i);
		EnableWindow(hWnd, phDesktop[i] ? TRUE : FALSE);
	}
}

//静态控件的子类化
LRESULT CALLBACK ThumbStaticWndProc(
	HWND hWnd, 
	UINT uMsg, 
	WPARAM wParam, 
	LPARAM lParam
	)
{
	switch(uMsg)
	{
	case WM_PAINT://这里主要负责将位图缩小绘制
		{
			HDC				hDC;
			PAINTSTRUCT		ps;
			RECT			rect;
			HDC				hMemDC;
			HBITMAP			hOldBimap;
			BITMAP			bitmap;
			HFONT			hOldFont;
			INT				iOldStretchMode;
			
			hDC = BeginPaint(hWnd, &ps);
			GetClientRect(hWnd, &rect);
			FillRect(hDC, &rect, GetSysColorBrush(COLOR_WINDOW));//填充为窗口色
			if(g_hDrwBmp)
			{
				if(GetObject(g_hDrwBmp, sizeof(BITMAP), &bitmap))
				{
					hMemDC = CreateCompatibleDC(hDC);		
					hOldBimap = (HBITMAP)SelectObject(hMemDC, g_hDrwBmp);

					iOldStretchMode = SetStretchBltMode(hDC, HALFTONE);
					StretchBlt(hDC, rect.left, rect.top, rect.right, rect.bottom, hMemDC, 0, 0, bitmap.bmWidth, bitmap.bmHeight, SRCCOPY);
					SetStretchBltMode(hDC, iOldStretchMode);

					SelectObject(hMemDC, hOldBimap);
					DeleteDC(hMemDC);
				}
			}
			else
			{
				SetBkMode(hDC, TRANSPARENT);
				hOldFont = (HFONT)SelectObject(hDC, GetStockObject(SYSTEM_FIXED_FONT));

				DrawText(hDC,
					_T("该桌面还没有快照"),
					-1,
					&rect,
					DT_CENTER | DT_VCENTER | DT_SINGLELINE);

				SelectObject(hDC, hOldFont);
				SetBkMode(hDC, OPAQUE);
			}
			EndPaint(hWnd, &ps);
		}
		return FALSE;
	}
	return CallWindowProc(g_lpfnStcWndFunc, hWnd, uMsg, wParam, lParam);
}

INT_PTR CALLBACK MainDlgProc(
	HWND hDlg,
	UINT message,
	WPARAM wParam,
	LPARAM lParam
	)
{
	static HWND				s_hThumbStatic;

	switch (message)
	{
	case WM_PAINT:
		{
			HDC				hDC;
			PAINTSTRUCT		ps;

			hDC = BeginPaint(hDlg, &ps);
			EndPaint(hDlg, &ps);
		}
		break;
	case WM_INITDIALOG:
		{
			HWND			hwndFocus = (HWND) wParam;
			LPARAM			lInitParam = lParam;

			SendMessage(hDlg, WM_SETICON, ICON_SMALL, (LPARAM)LoadIcon(g_hinst, MAKEINTRESOURCE(IDI_MAIN)));

			s_hThumbStatic = GetDlgItem(hDlg, IDC_STATIC_THUMB);
			
			SetDlgItemText(hDlg, IDC_EDIT_SELECT, g_aszDesktopName[g_iSelectIndex]);//设置选中桌面名
			SetDlgItemText(hDlg, IDC_EDIT_CURRENT, g_aszDesktopName[g_iCurrentIndex]);//设置当前桌面名
			
			g_hDrwBmp = g_ahBitmap[g_iSelectIndex];//当前选中位图
			g_lpfnStcWndFunc = (WNDPROC)SetWindowLongPtr(s_hThumbStatic, GWLP_WNDPROC, (LONG_PTR)ThumbStaticWndProc);//子类化

			EnableButton(hDlg, g_ahDesktop);//启用按钮

			RegisterHotKey(hDlg, 1001, MOD_SHIFT | MOD_ALT ,'D');//注册热键
			RegisterHotKey(hDlg, 1002, MOD_SHIFT | MOD_ALT ,'G');
			RegisterHotKey(hDlg, 1003, MOD_SHIFT | MOD_ALT ,'H');
			RegisterHotKey(hDlg, 1004, MOD_SHIFT | MOD_ALT ,'S');
		}
		break;
	case WM_HOTKEY:
		{
			int				idHotKey = (int) wParam;
			UINT			fuModifiers = (UINT) LOWORD(lParam);
			UINT			uVirtKey = (UINT) HIWORD(lParam);

			switch(idHotKey)
			{
			case 1001://切换到默认桌面
				{
					if(g_iCurrentIndex == 0)//已经是默认桌面了
						break;

					SendMessage(hDlg, WM_COMMAND, MAKEWPARAM(IDC_DESKTOP0, 0), 0);
					SendMessage(hDlg, WM_COMMAND, MAKEWPARAM(IDC_BTN_SWITCH, 0), 0);
				}
				break;
			case 1002://在已有的桌面来回切换
				{
					INT				nIndex;
					INT				i;

					nIndex = g_iCurrentIndex;
					for(i=nIndex+1; i<10; i++)
					{
						if(g_ahDesktop[i])
							break;
					}	

					if(i == 10)
					{
						for(i=0; i<nIndex; i++)
						{
							if(g_ahDesktop[i])
								break;
						}

						if(i == nIndex)
							break;
					}

					SendMessage(hDlg, WM_COMMAND, MAKEWPARAM(IDC_DESKTOP0 + i, 0), 0);
					SendMessage(hDlg, WM_COMMAND, MAKEWPARAM(IDC_BTN_SWITCH, 0), 0);
				}
				break;
			case 1003://隐藏窗体
				{
					g_bHide = TRUE;
					ShowWindow(hDlg, SW_HIDE);
				}
				break;
			case 1004://显示窗体
				{
					g_bHide = FALSE;
					ShowWindow(hDlg, SW_NORMAL);
				}
				break;
			}
		}
		break;
	case WM_COMMAND:
		{
			WORD			wNotifyCode = HIWORD(wParam);
			WORD			wID = LOWORD(wParam);
			HWND			hwndCtl = (HWND) lParam;

			switch(wID)
			{
			case IDC_BTN_ABOUT:
				{
					MessageBox(hDlg, _T("本程序有以下快捷键,欢迎大家一起学习交流\r\n\r\n")
						_T("Shitf+Alt+D\t\t切换到默认桌面\r\n")
						_T("Shitf+Alt+G\t\t循环切换每个桌面\r\n")
						_T("Shitf+Alt+H\t\t隐藏窗体\r\n")
						_T("Shitf+Alt+S\t\t显示窗体\r\n"),
						_T("关于..."), MB_OK);
				}
				break;
			case IDC_BTN_SWITCH:
				{
					if(g_iSelectIndex == g_iCurrentIndex)
					{
						MessageBox(hDlg, _T("已经是该桌面了"), _T("提示"), MB_OK | MB_ICONINFORMATION);
						break;
					}

					SendMessage(hDlg, WM_CLOSE, 0, TRUE);
				}
				break;
			case IDC_BTN_SHELL:
				{
					PVOID				pValue;

					if(GetShellWindow() == NULL)//判断是否存在Shell
					{
						MyWow64DisableWow64FsRedirection(&pValue);
						StartProcess(g_aszDesktopName[g_iCurrentIndex],  _T("C:\\Windows\\Explorer.exe"));
						StartProcess(g_aszDesktopName[g_iCurrentIndex], _T("C:\\Windows\\System32\\ctfmon.exe"));
						MyWow64RevertWow64FsRedirection(pValue);	
					}
				}
				break;
			case IDC_BTN_TASKMGR:
				{
					PVOID				pValue;

					MyWow64DisableWow64FsRedirection(&pValue);
					StartProcess(g_aszDesktopName[g_iCurrentIndex], _T("C:\\Windows\\System32\\taskmgr.exe"));
					MyWow64RevertWow64FsRedirection(pValue);
				}
				break;
			case IDC_BTN_NEW:
				{
					INT					i;

					for(i=0; i<10; i++)
					{
						if(i != 0 && !g_ahDesktop[i])
							break;
					}
					if(i == 10)
					{
						MessageBox(hDlg, _T("由于桌面已满,无法新建桌面"), _T("错误"), MB_OK | MB_ICONERROR);
						break;
					}
					
					g_ahDesktop[i] = CreateDesktop(
						g_aszDesktopName[i],
						NULL,
						NULL,
						NULL,
						GENERIC_ALL,
						NULL);
					if(g_ahDesktop[i] == NULL)
					{
						MessageBox(hDlg, _T("创建桌面时发生错误,无法新建桌面"), _T("错误"), MB_OK | MB_ICONERROR);
						break;
					}

					EnableWindow(GetDlgItem(hDlg, IDC_DESKTOP0 + i), TRUE);
				}
				break;
			case IDC_DESKTOP0:
			case IDC_DESKTOP1:
			case IDC_DESKTOP2:
			case IDC_DESKTOP3:
			case IDC_DESKTOP4:
			case IDC_DESKTOP5:
			case IDC_DESKTOP6:
			case IDC_DESKTOP7:
			case IDC_DESKTOP8:
			case IDC_DESKTOP9:
			case IDC_DESKTOP10:
			case IDC_DESKTOP11:
				{
					g_iSelectIndex =  wID - IDC_DESKTOP0;
					SetDlgItemText(hDlg, IDC_EDIT_SELECT, g_aszDesktopName[g_iSelectIndex]);
					
					g_hDrwBmp =  g_ahBitmap[g_iSelectIndex];
					InvalidateRect(s_hThumbStatic, NULL, TRUE);
					UpdateWindow(s_hThumbStatic);
				}
				break;
			}
		}
		break;
	case WM_SYSCOMMAND:
		{
			DWORD			dwType = (DWORD)wParam;

			switch(dwType)
			{
			case SC_MINIMIZE:
				{
					MessageBox(hDlg, _T("使用快捷键Alt + Shift + S显示窗体"), _T("提示"), 0);
										
					g_bHide = TRUE;
					ShowWindow(hDlg, SW_HIDE);
				}
				return TRUE;
			}
		}
		break;
	case WM_NCPAINT:
		{
			if(g_bHide)
				ShowWindow(hDlg, SW_HIDE);
		}
		break;
	case WM_CLOSE:
		{
			EndDialog(hDlg, (INT_PTR)lParam);
		}
		break;
	}

	return FALSE;
}

DWORD WINAPI StartWindow(
	LPVOID lpParameter
	)
{
	TCHAR			szMsg[512];
	
	if(g_iSelectIndex < 0 || g_iSelectIndex >= MAXDESKNUM)
	{
		MessageBox(NULL, szMsg, _T("桌面选择不正确"), MB_OK | MB_ICONERROR);
		return 1;
	}

	if(!SetThreadDesktop(g_ahDesktop[g_iSelectIndex]))//设置线程桌面为选中的桌面
	{
		wsprintf(szMsg, _T("无法设置线程桌面,错误:%d"), GetLastError());
		MessageBox(NULL, szMsg, _T("错误"), MB_OK | MB_ICONERROR);
		return 1;
	}

	if(!SwitchDesktop(g_ahDesktop[g_iSelectIndex]))//切换到选中的桌面
	{
		wsprintf(szMsg, _T("无法切换桌面,错误:%d"), GetLastError());
		MessageBox(NULL, szMsg, _T("错误"), MB_OK | MB_ICONERROR);
		return 1;
	}
	
	g_iCurrentIndex = g_iSelectIndex;
	if(!DialogBox(g_hinst, (LPCTSTR)IDD_MAIN, NULL, MainDlgProc))//创建对话框
		return 1;

	Sleep(100);
	if(g_ahBitmap[g_iCurrentIndex])
	{
		DeleteObject(g_ahBitmap[g_iCurrentIndex]);
	}
	g_ahBitmap[g_iCurrentIndex] = GetScreenBitmap();//获取当前屏幕位图

	return 0;
}

//主函数
int APIENTRY _tWinMain(
	HINSTANCE hInstance,
	HINSTANCE hPrevInstance,
	LPTSTR lpCmdLine,
	int nCmdShow
	)
{
	HANDLE			hMutex;
	HANDLE			hThread;
	DWORD			dwExitCode;
	
	g_hinst = hInstance;
	if (hMutex = CreateMutex(NULL, FALSE, _T("VirtualDesktop")))
	{
		if (GetLastError() != ERROR_ALREADY_EXISTS)
		{
			InitAllDesktop();			
			if ((g_iSelectIndex = GetCurrentDesktopIndex()) == -1)
			{
				if(MessageBox(NULL,
					_T("检测到程序运行在一个无法识别的桌面,是否切换到默认桌面"),
					_T("提示"),
					MB_YESNO | MB_ICONQUESTION) == IDYES)
				{
					SwitchDesktop(g_ahDesktop[0]);
				}
			}
			else
			{
				do
				{
					dwExitCode = 1;
					hThread = CreateThread(NULL,
						NULL,
						StartWindow,
						NULL,
						NULL,
						NULL);//创建一个干净的线程
					if(hThread)
					{
						WaitForSingleObject(hThread, INFINITE);//等待线程结束
						GetExitCodeThread(hThread, &dwExitCode);//获取线程退出码
						CloseHandle(hThread);
					}
					else
					{
						MessageBox(NULL, _T("创建线程失败"), _T("错误"), MB_OK | MB_ICONERROR);
						break;
					}
				}
				while(dwExitCode == 0);
			}
			UnInitAllDesktop();
		}
		else
		{
			MessageBox(NULL, _T("程序只能运行一个实例"), _T("提示"), MB_OK | MB_ICONINFORMATION);
		}

		CloseHandle(hMutex);
	}
	else
	{
		MessageBox(NULL, _T("无法创建互斥体"), _T("错误"), MB_OK | MB_ICONERROR);
		return 1;
	}

	return 0;
}